﻿#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

void blur_1(Mat& inputImage, Mat& outputImage, int hang, int lie);//均值滤波
void blur_2(Mat& inputImage, Mat& outputImage, int hang, int lie);//高斯滤波
void blur_3(Mat& inputImage, Mat& outputImage, int hang, int lie);//双边滤波

int main()
{
    //读入图像
    Mat image = imread("1.jpg", 0);
    Mat dstimage;
    //建立窗口
    namedWindow("原图");
    namedWindow("效果图");
    //展示原图
    imshow("原图", image);
    //建立一个跟原图大小，尺寸一致的输出图像
    dstimage.create(image.rows, image.cols, image.type());
    //均值滤波函数
    blur_1(image, dstimage, 5, 5);
    //输出效果图
    imshow("效果图", dstimage);
    waitKey(0);
    return 0;
}
void blur_1(Mat& inputImage, Mat& outputImage, int hang, int lie)
{
    int num1, num2;
    int sum = 0;
    num1 = (hang - 1) / 2;
    num2 = (lie - 1) / 2;
    //将输入图像复制给输出图像
    outputImage = inputImage.clone();
    //记录图像的行数，列数
    int rowNumber = outputImage.rows;
    int colNumber = outputImage.cols;
    int tongdao = outputImage.channels();
    
        /*...........................at遍历像素................................*/
    for (int i = num1; i < rowNumber - num1; i++)
    {
        for (int j = num2; j < colNumber - num2; j++)
        {
            if (tongdao == 1)
            {
                int avr = 0;
                //求出以每个像素为中心点，滤波核内所有像素点的和
                for (int h = 0; h < hang; h++)
                {
                    for (int l = 0; l < lie; l++)
                    {
                        avr += inputImage.at<uchar>(i - num1 + h, j - num2 + l);
                    }

                }
                outputImage.at<uchar>(i, j) = avr / (hang * lie);
            }
            if (tongdao == 3)
            {
                int avr1 = 0;
                int avr2 = 0;
                int avr3 = 0;
                //求出以每个像素为中心点，滤波核内所有像素点的和
                for (int h = 0; h < hang; h++)
                {
                    for (int l = 0; l < lie; l++)
                    {
                        avr1 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[0];
                        avr2 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[1];
                        avr3 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[2];
                    }

                }
                outputImage.at<Vec3b>(i, j)[0] = avr1 / (hang * lie);
                outputImage.at<Vec3b>(i, j)[1] = avr2 / (hang * lie);
                outputImage.at<Vec3b>(i, j)[2] = avr3 / (hang * lie);


            }
        }
    }
}
void blur_2(Mat& inputImage, Mat& outputImage, int hang, int lie)
{
    double sigma = 2;           //偏差值。
    double pia = 3.14;          //Π。
    double a[50][50];           //权重数组。
    double sum = 0;               //因权重和不为一，要归一化，求原权重和。
    int num1 = (hang - 1) / 2;
    int num2 = (lie - 1) / 2;
    //将输入图像复制给输出图像
    outputImage = inputImage.clone();
    //记录图像的行数，列数
    int rowNumber = outputImage.rows;
    int colNumber = outputImage.cols;
    int tongdao = outputImage.channels();
    /*利用高斯公式求出核内各区域权重以及权重和*/
    for (int m = 0; m < hang; m++)
    {
        for (int n = 0; n < lie; n++)
        {
            a[m][n] = (exp(-((m - num1) * (m - num1) + (n - num2) * (n - num2)) / (2 * sigma * sigma))) / (2 * pia * sigma * sigma);
            sum += a[m][n];
        }
    }
    /*因原权重和不为1，先进行归一化*/
    for (int m = 0; m < hang; m++)
    {
        for (int n = 0; n < lie; n++)
        {
            a[m][n] = a[m][n] / sum;
            printf("%lf \n", a[m][n]);
        }
    }
    for (int i = num1; i < rowNumber - num1; i++)
    {
        for (int j = num2; j < colNumber - num2; j++)
        {
            //求出以每个像素为中心点，滤波核内所有像素点的和
             /*灰度图*/
            if (tongdao == 1)
            {
                int avr = 0;      //权重与相应像素值相乘后的和
                for (int m = 0; m < hang; m++)
                {
                    for (int n = 0; n < lie; n++)
                    {
                        avr += inputImage.at<uchar>(i - num1 + m, j - num2 + n) * a[m][n];
                    }
                }
                outputImage.at<uchar>(i, j) = avr;
            }
            /*彩图*/
            if (tongdao == 3)
            {
                //权重与相应像素值相乘后的和
                int avr1 = 0;
                int avr2 = 0;
                int avr3 = 0;
                //求出以每个像素为中心点，滤波核内所有像素点的和
                for (int h = 0; h < hang; h++)
                {
                    for (int l = 0; l < lie; l++)
                    {
                        avr1 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[0] * a[h][l];
                        avr2 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[1] * a[h][l];
                        avr3 += inputImage.at<Vec3b>(i - num1 + h, j - num2 + l)[2] * a[h][l];
                    }

                }
                outputImage.at<Vec3b>(i, j)[0] = avr1;
                outputImage.at<Vec3b>(i, j)[1] = avr2;
                outputImage.at<Vec3b>(i, j)[2] = avr3;
            }
        }
    }

}
void blur_3(Mat& inputImage, Mat& outputImage, int hang, int lie)
{
    double sigma_d = 10;         //偏差值。
    double sigma_r = 10;
    double a[50][50];           //权重数组。
    double b[50][50];
    double c[50][50];
    double d[50][50];
    int num1 = (hang - 1) / 2;
    int num2 = (lie - 1) / 2;
    //将输入图像复制给输出图像
    outputImage = inputImage.clone();
    //记录图像的行数，列数 
    int rowNumber = outputImage.rows;
    int colNumber = outputImage.cols;
    int tongdao = outputImage.channels();
    /*利用高斯公式求出空间区域权重*/
    for (int m = 0; m < hang; m++)
    {
        for (int n = 0; n < lie; n++)
        {
            a[m][n] = exp(-(((m - num1) * (m - num1) + (n - num2) * (n - num2)) / (2 * sigma_d * sigma_d)));
        }
    }
    for (int i = num1; i < rowNumber - num1; i++)
    {
        for (int j = num2; j < colNumber - num2; j++)
        {

            /*利用高斯公式求出像素值区域权重*/
            for (int m = 0; m < hang; m++)
            {
                for (int n = 0; n < lie; n++)
                {
                    if (tongdao == 1)
                    {
                        b[m][n] = exp(-(inputImage.at<uchar>(i, j) - inputImage.at<uchar>(i - num1 + m, j - num2 + n)) * (inputImage.at<uchar>(i, j) - inputImage.at<uchar>(i - num1 + m, j - num2 + n)) / (2 * sigma_r * sigma_r));

                    }
                    if (tongdao == 3)
                    {
                        b[m][n] = exp(-(inputImage.at<Vec3b>(i, j)[0] + inputImage.at<Vec3b>(i, j)[1] + inputImage.at<Vec3b>(i, j)[2] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[0] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[1] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[2])
                            * (inputImage.at<Vec3b>(i, j)[0] + inputImage.at<Vec3b>(i, j)[1] + inputImage.at<Vec3b>(i, j)[2] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[0] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[1] - inputImage.at<Vec3b>(i - num1 + m, j - num2 + n)[2]) / (2 * sigma_r * sigma_r));

                    }
                }
            }
            /*求出双边滤波权重函数*/
            double sum = 0;
            for (int m = 0; m < hang; m++)
            {

                for (int n = 0; n < lie; n++)
                {
                    c[m][n] = a[m][n] * b[m][n];
                    sum += c[m][n];
                }
            }
            /*求出滤波输出值*/
            double avr = 0;
            for (int m = 0; m < hang; m++)
            {
                for (int n = 0; n < lie; n++)
                {
                    avr += inputImage.at<uchar>(i - num1 + m, j - num2 + n) * c[m][n] / sum;

                }
            }
            outputImage.at<uchar>(i, j) = avr;

        }
    }

}